#include "adc.h"

__IO uint8_t AnalogInputs[NO_OF_ADC_CH];

const adc_struct ADC_channels[] = 
{
  {RCC_AHBPeriph_GPIOC, GPIOC, GPIO_Pin_0,  RCC_AHBPeriph_ADC12, ADC1, ADC_Channel_6,  1}, //ADC1_IN6  - PC0  - ch1  - yel-left vertical
  {RCC_AHBPeriph_GPIOC, GPIOC, GPIO_Pin_1,  RCC_AHBPeriph_ADC12, ADC1, ADC_Channel_7,  2}, //ADC1_IN7  - PC1  - ch2  - yel-left horizontal
  {RCC_AHBPeriph_GPIOC, GPIOC, GPIO_Pin_2,  RCC_AHBPeriph_ADC12, ADC1, ADC_Channel_8,  3}, //ADC1_IN8  - PC2  - ch3  - yel-right vertical
  {RCC_AHBPeriph_GPIOC, GPIOC, GPIO_Pin_3,  RCC_AHBPeriph_ADC12, ADC1, ADC_Channel_9,  4}, //ADC1_IN9  - PC3  - ch4  - yel-right horizontal
  {RCC_AHBPeriph_GPIOF, GPIOF, GPIO_Pin_2,  RCC_AHBPeriph_ADC12, ADC1, ADC_Channel_10, 5}, //ADC1_IN10 - PF2  - ch5  - red-left vertical
  {RCC_AHBPeriph_GPIOF, GPIOF, GPIO_Pin_4,  RCC_AHBPeriph_ADC12, ADC1, ADC_Channel_5,  6}, //ADC1_IN5  - PF4  - ch6  - red-left horizontal

  {RCC_AHBPeriph_GPIOC, GPIOC, GPIO_Pin_4,  RCC_AHBPeriph_ADC12, ADC2, ADC_Channel_5,  1}, //ADC2_IN5  - PC4  - ch7  - red-right vertical
  {RCC_AHBPeriph_GPIOC, GPIOC, GPIO_Pin_5,  RCC_AHBPeriph_ADC12, ADC2, ADC_Channel_11, 2}, //ADC2_IN11 - PC5  - ch8  - red-right horizontal
  {RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_2,  RCC_AHBPeriph_ADC12, ADC2, ADC_Channel_12, 3}, //ADC2_IN12 - PB2  - ch9  - green-left vertical

  {RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_12, RCC_AHBPeriph_ADC34, ADC4, ADC_Channel_3,  1}, //ADC4_IN3  - PB12 - ch10 - green-right vertical
  {RCC_AHBPeriph_GPIOD, GPIOD, GPIO_Pin_8,  RCC_AHBPeriph_ADC34, ADC4, ADC_Channel_12, 2}, //ADC4_IN12 - PD8  - ch11 - green-right horizontal
  {RCC_AHBPeriph_GPIOD, GPIOD, GPIO_Pin_9,  RCC_AHBPeriph_ADC34, ADC4, ADC_Channel_13, 3}, //ADC4_IN13 - PD9  - ch12 - speed potentiometer
  {RCC_AHBPeriph_GPIOD, GPIOD, GPIO_Pin_10, RCC_AHBPeriph_ADC34, ADC4, ADC_Channel_7,  4}, //ADC34_IN7 - PD10 - ch13 - spare
};

#define ADC1_offset 0
#define ADC1_channels 6

#define ADC2_offset 6
#define ADC2_channels 3

#define ADC4_offset 9
#define ADC4_channels 4

void ADC_Config(void)
{
	
  ADC_InitTypeDef         ADC_InitStructure;
  ADC_CommonInitTypeDef   ADC_CommonInitStructure;
  NVIC_InitTypeDef        NVIC_InitStructure;
  GPIO_InitTypeDef        GPIO_InitStructure;
  uint32_t i;
  
  
  /* Configure the ADC clock */
  RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div64);
  RCC_ADCCLKConfig(RCC_ADC34PLLCLK_Div64);

  ADC_StructInit(&ADC_InitStructure);
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  for (i = 0; i < NO_OF_ADC_CH; i++)
  {
    /* Enable ADC clock */
    RCC_AHBPeriphClockCmd(ADC_channels[i].RCC_AHBPeriph_ADC, ENABLE);
    /* GPIOx Periph clock enable */
    RCC_AHBPeriphClockCmd(ADC_channels[i].RCC_AHBPeriph_GPIO, ENABLE);
    /* Configure ADC channels as analog input */
    GPIO_InitStructure.GPIO_Pin = ADC_channels[i].GPIO_Pin;
    GPIO_Init(ADC_channels[i].GPIO_Port, &GPIO_InitStructure);
  }

  /* Calibration procedure */  
  ADC_VoltageRegulatorCmd(ADC1, ENABLE);
  ADC_VoltageRegulatorCmd(ADC2, ENABLE);
  //ADC_VoltageRegulatorCmd(ADC3, ENABLE);
  ADC_VoltageRegulatorCmd(ADC4, ENABLE);
  
  /* Insert delay equal to 10 µs */
  i = 0xFFFF;
  while(--i);
  
  ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
  ADC_SelectCalibrationMode(ADC2, ADC_CalibrationMode_Single);
  //ADC_SelectCalibrationMode(ADC3, ADC_CalibrationMode_Single);
  ADC_SelectCalibrationMode(ADC4, ADC_CalibrationMode_Single);

  ADC_StartCalibration(ADC1);
  ADC_StartCalibration(ADC2);
  //ADC_StartCalibration(ADC3);
  ADC_StartCalibration(ADC4);
  
  while(ADC_GetCalibrationStatus(ADC1) != RESET );
  while(ADC_GetCalibrationStatus(ADC2) != RESET );
  //while(ADC_GetCalibrationStatus(ADC3) != RESET );
  while(ADC_GetCalibrationStatus(ADC4) != RESET );
     
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                                                                    
  ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;                    
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;             
  ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot;                  
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;
  ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
  ADC_CommonInit(ADC2, &ADC_CommonInitStructure);
  //ADC_CommonInit(ADC3, &ADC_CommonInitStructure);
  ADC_CommonInit(ADC4, &ADC_CommonInitStructure);
  
  ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; 
  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;         
  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Enable;   
  ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;  
  ADC_InitStructure.ADC_NbrOfRegChannel = ADC1_channels;
  ADC_Init(ADC1, &ADC_InitStructure);
  //ADC_AutoDelayCmd(ADC1, ENABLE);
  ADC_InitStructure.ADC_NbrOfRegChannel = ADC2_channels;
  ADC_Init(ADC2, &ADC_InitStructure);
//  ADC_InitStructure.ADC_NbrOfRegChannel = ADC3_channels;
//  ADC_Init(ADC3, &ADC_InitStructure);
  ADC_InitStructure.ADC_NbrOfRegChannel = ADC4_channels;
  ADC_Init(ADC4, &ADC_InitStructure);

  for (i = 0; i < ADC1_channels + ADC2_channels + ADC4_channels; i++)
  {
    // ADC regular channel configuration
    ADC_RegularChannelConfig(ADC_channels[i].ADCx, ADC_channels[i].ADC_Channel, ADC_channels[i].ADC_Rank, ADC_SampleTime_7Cycles5);
  }

   
  /* Enable the ADC global Interrupts */
  NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  //NVIC_InitStructure.NVIC_IRQChannel = ADC3_IRQn;
  //NVIC_Init(&NVIC_InitStructure);
  NVIC_InitStructure.NVIC_IRQChannel = ADC4_IRQn;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable the ADC Interrupt Requests */
  ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
  ADC_ITConfig(ADC2, ADC_IT_EOC, ENABLE);
  //ADC_ITConfig(ADC3, ADC_IT_EOC, ENABLE);
  ADC_ITConfig(ADC4, ADC_IT_EOC, ENABLE);
  
  /* Enable ADC */
  ADC_Cmd(ADC1, ENABLE);
  ADC_Cmd(ADC2, ENABLE);
  //ADC_Cmd(ADC3, ENABLE);
  ADC_Cmd(ADC4, ENABLE);
  
  /* wait for ADRDY */
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
  while(!ADC_GetFlagStatus(ADC2, ADC_FLAG_RDY));
  //while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_RDY));
  while(!ADC_GetFlagStatus(ADC4, ADC_FLAG_RDY));
  
  /* Start ADC Software Conversion */ 
  ADC_StartConversion(ADC1);
  ADC_StartConversion(ADC2);
  //ADC_StartConversion(ADC3);
  ADC_StartConversion(ADC4);
}

void ADC12_Handler (void)
{
  static uint32_t vCurADC1Channel = 0;
  static uint32_t vCurADC2Channel = 0;

  if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
  {
    AnalogInputs[ADC1_offset + vCurADC1Channel] = (ADC_GetConversionValue(ADC1) >> 4) & 0xFF;

    if (++vCurADC1Channel == ADC1_channels)
    {
      vCurADC1Channel = 0;
    }
  }

  if (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC))
  {
    AnalogInputs[ADC2_offset + vCurADC2Channel] = (ADC_GetConversionValue(ADC2) >> 4) & 0xFF;

    if (++vCurADC2Channel == ADC2_channels)
    {
      vCurADC2Channel = 0;
    }
  }

}

void ADC4_Handler (void)
{
  static uint32_t vCurADC4Channel = 0;

  if (ADC_GetFlagStatus(ADC4, ADC_FLAG_EOC))
  {
    AnalogInputs[ADC4_offset + vCurADC4Channel] = (ADC_GetConversionValue(ADC4) >> 4) & 0xFF;

    if (++vCurADC4Channel == ADC4_channels)
    {
      vCurADC4Channel = 0;
    }
  }

}
